package biz

import (
	"New-lesson-part2/custom_error"
	"New-lesson-part2/internal"
	"New-lesson-part2/model"
	"New-lesson-part2/proto/pb"
	"context"
	"errors"
	"github.com/golang/protobuf/ptypes/empty"
	"sync"
)

type StockServer struct {
}

var m sync.RWMutex //给代码加锁.

func (s StockServer) SetStock(ctx context.Context, req *pb.ProductStockItem) (*empty.Empty, error) {
	//参数校验
	var stock model.Stock
	internal.DB.Where("product_id=?", req.ProductId).Find(&stock)
	if stock.ID < 1 {
		stock.ProductId = req.ProductId

	}
	stock.Num = req.Num
	save := internal.DB.Save(&stock)
	if save.Error != nil {
		return nil, errors.New(custom_error.StockSaveFailed)
	}

	return &empty.Empty{}, nil
}

func (s StockServer) StockDetail(ctx context.Context, req *pb.ProductStockId) (*pb.ProductStockItem, error) {
	var stock model.Stock
	var res *pb.ProductStockItem
	r := internal.DB.Where("product_id=?", req.ProductId).First(&stock)
	if r.Error != nil {
		return nil, errors.New(custom_error.StockSystemError)
	}
	if r.RowsAffected < 1 {
		return nil, errors.New(custom_error.ParameterError)
	}
	res = ConvertStockModel2Pb(stock)

	return res, nil
}

// Sell 扣减库存
func (s StockServer) Sell(ctx context.Context, req *pb.SellItem) (*empty.Empty, error) {
	m.Lock()
	defer m.Unlock()
	tx := internal.DB.Begin()
	var stock model.Stock
	for _, i := range req.StockItemList {
		first := tx.Where("product_id=?", i.ProductId).First(&stock)
		if first.RowsAffected < 1 {
			return nil, errors.New(custom_error.ProductDataIsNotExists)
		}
		if stock.Num < i.Num {
			tx.Rollback()
			return nil, errors.New(custom_error.StockIsNotEnough)
		}

		stock.Num -= i.Num //这里是减库存 千万不要忘记
		save := tx.Save(&stock)
		if save.RowsAffected < 1 {
			tx.Rollback()
			return nil, errors.New(custom_error.UpdateStockFailed)
		}

		if save.Error != nil {
			tx.Rollback()
			return nil, errors.New(custom_error.StockSystemError)
		}
	}
	tx.Commit()

	return &empty.Empty{}, nil
}

func (s StockServer) BackStock(ctx context.Context, req *pb.SellItem) (*empty.Empty, error) {
	//什么时候会触发归还库存?
	//订单超时
	//订单创建失败.
	//手动归还.
	m.Lock()
	defer m.Unlock()
	tx := internal.DB.Begin()
	for _, item := range req.StockItemList {
		var stock model.Stock
		res := tx.Where("product_id = ?", item.ProductId).First(&stock)
		if res.Error != nil {
			tx.Rollback()
			return nil, errors.New(custom_error.StockSystemError)
		}
		if res.RowsAffected < 1 {
			tx.Rollback()
			return nil, errors.New(custom_error.ProductDataIsNotExists)
		}
		stock.Num += item.Num
		save := tx.Save(&stock)
		if save.Error != nil {
			tx.Rollback()
			return nil, errors.New(custom_error.StockSystemError)
		}
		if save.RowsAffected < 1 {
			tx.Rollback()
			return nil, errors.New(custom_error.ProductDataIsNotExists)
		}
	}
	tx.Commit()
	return &empty.Empty{}, nil
}

func ConvertStockModel2Pb(s model.Stock) *pb.ProductStockItem {
	res := pb.ProductStockItem{
		ProductId: s.ProductId,
		Num:       s.Num,
	}
	return &res
}
